/**
 * Created by ZHOUSH on 11/27/2015.
 */
var app = angular.module('console', []);
var I64BIT_TABLE =
    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'.split('');
function fHash(input) {
    var hash = 5381;
    var i = input.length - 1;
    if (typeof input == 'string') {
        for (; i > -1; i--)
            hash += (hash << 5) + input.charCodeAt(i);
    } else {
        for (; i > -1; i--)
            hash += (hash << 5) + input[i];
    }
    var value = hash & 0x7FFFFFFF;
    var retValue = '';
    do {
        retValue += I64BIT_TABLE[value & 0x3F];
    }
    while (value >>= 6);
    return retValue;
}
app.controller('consoleController', function ($scope, $http) {
    $('#sql_upload').fileinput({
        uploadUrl: 'api/file/upload/sql'
    });
    $scope.sqlUploaded = [];
    $('#sql_upload').on('fileuploaded', function (event, data) {
        $scope.$apply(function () {
            $scope.sqlUploaded = data.response.map(function(item) {
                return {
                    original: item.original,
                    hash: item.hash,
                    time: (new Date(item.time)).toTimeString()
                }
            });
        });
    });
    $('#sql_upload').on('filebatchuploadcomplete', function (event, files) {
        $('#sql_upload').fileinput('reset');
    });
    $scope.connection = null;
    $scope.tab = 'DSQL';
    $http.get('api/connections/all').then(function (res) {
        $scope.dbList = res.data;
    });
    $scope.dbList = [];
    $scope.connect = function (item) {
        item.checked = true;
        $http.post('api/connections/connect', item).then(function (res) {
            item.key = res.data;
            item.status = 'CONNECTED'
        });
    };
    $scope.close = function (item) {
        $http.post('api/connections/close', {
            connection: item.key
        }).then(function (res) {
            delete item.key;
            item.status = 'CLOSED'
        });
    };

    var editor = CodeMirror.fromTextArea(document.getElementById('sql-editor'), {
        mode: 'text/x-plsql',
        indentWithTabs: true,
        smartIndent: true,
        lineNumbers: true,
        matchBrackets: true,
        autofocus: true,
        extraKeys: {"Ctrl-Space": "autocomplete"},
        value: 'select * from dual;'
    });
    $scope.allSqls = 'NO SQL;';
    var parseSql = function (cm) {
        var sqls = [], text = '', last_ln = 0, last_ch = 0;
        cm.eachLine(function (lineHandler) {
            var ln = cm.getLineNumber(lineHandler), sql = cm.getLine(ln);
            if (text == '' && sqls.length > 0) {
                last_ln = ln;
                last_ch = 0;
            }
            var last = cm.getLineTokens(ln).reduce(function (pre, item) {
                if (item.string == ';') {
                    pre.push(item.end);
                }
                return pre;
            }, []).reduce(function (pre, cur) {
                text += sql.substring(pre, cur);
                if (text) {
                    sqls.push({
                        sql: text,
                        start: {
                            line: last_ln,
                            ch: last_ch
                        },
                        end: {
                            line: ln,
                            ch: cur
                        }
                    });
                    text = '';
                    last_ln = ln;
                    last_ch = cur;
                }
                return cur;
            }, 0);
            if (last == 0) {
                text += sql.substring(last, sql.length) + '\r\n';
            } else if (last != sql.length) {
                text = sql.substring(last, sql.length);
            } else {
                text = '';
            }
        });
        return sqls;
    };
    var foundSql = function (cm, from, to) {
        var sqls = parseSql(cm);
        var is_in = function (item, cur) {
            if (item.start.line == cur.line && item.end.line > cur.line) {
                return item.start.ch <= cur.ch;
            }
            if (item.end.line == cur.line && item.start.line < cur.line) {
                return item.end.ch >= cur.ch;
            }
            if (item.end.line == cur.line && item.start.line == cur.line) {
                return item.start.ch <= cur.ch && item.end.ch >= cur.ch;
            }
            return item.start.line < cur.line && item.end.line > cur.line;
        };
        var fromSql = sqls.filter(function (item) {
            return is_in(item, from);
        })[0];
        var fromIdx = sqls.indexOf(fromSql);
        var toSql = sqls.filter(function (item) {
            return is_in(item, to);
        })[0];
        var toIdx = sqls.indexOf(toSql);
        if (fromIdx > toIdx) {
            var temp = toIdx;
            toIdx = fromIdx;
            fromIdx = temp;
        }
        if (from.line == to.line
            && from.ch == to.ch
            && from.line == sqls[fromIdx].start.line
            && from.ch == sqls[fromIdx].start.ch) {
            toIdx--;
        }
        cm.setSelection(sqls[fromIdx].start, sqls[toIdx].end);
        return sqls.slice(fromIdx, toIdx + 1);
    };
    var listSql = function (cm) {
        var head = cm.getCursor('head');
        var anchor = cm.getCursor('anchor');
        var sqls = foundSql(cm, head, anchor);
        var hashed = [];
        return sqls.reduce(function (pre, item) {
            var hash = fHash(item.sql);
            if (hashed.indexOf(hash) >= 0) {
                return pre;
            }
            pre.push({
                sql: item.sql,
                name: hash,
                start: item.start,
                end: item.end
            });
            hashed.push(hash);
            return pre;
        }, []);
    };
    $scope.sqlList = [];
    $scope.list = function () {
        $scope.sqlList = listSql(editor);
    };
    $scope.listCount = function () {
        $scope.sqlList = listSql(editor);
    };
    var resulted = function (data) {
        var header = [];
        for (var prop in data[0]) {
            if (data[0].hasOwnProperty(prop)) {
                header.push(prop);
            }
        }
        $scope.resultSets.push({
            header: header,
            rows: data
        });
    };
    $scope.resultSets = [];
    $scope.sqlQuery = function (item, mode) {
        $scope.resultSets = [];
        var reqs = $scope.dbList.reduce(function (pre, conn) {
            if (!conn.checked) return pre;
            var obj = {
                conn: conn.key,
                sql: item.sql
            };
            if (mode == 'csv' || mode == 'json') {
                obj.type = mode;
                obj.name = conn.key + '_' + item.name + '.' + mode;
            }
            pre.push(obj);
            return pre;
        }, []);
        reqs.forEach(function (req) {
            var url = 'api/query/' + (mode == 'count' ? mode : 'query');
            $http.post(url, req).success(function (resp) {
                if (!req.name || !req.type) {
                    resulted(resp.data);
                } else {
                    var anchor = angular.element('<a/>');
                    anchor.attr({
                        href: 'data:attachment/' + req.type + ';charset=utf-8,' + encodeURI(resp),
                        target: '_blank',
                        download: req.name
                    })[0].click();
                }
            })
        })
    };
    var now = new Date();
    $scope.fileList = [];
    $http.post('api/file/list', {
        //from: new Date(now.getFullYear(), now.getMonth(), now.getDate()),
        //to: new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1)
    }).success(function (data) {
        $scope.fileList = data.map(function (item) {
            return {
                original: item.original,
                hash: item.hash,
                time: (new Date(+item.time)).toTimeString(),
                data: item.data
            }
        });
    });
    $scope.fileExecute = function (item) {
        var conns = $scope.dbList.reduce(function (pre, cur) {
            if (cur.checked) {
                pre.push(cur);
            }
            return pre;
        }, []);
        conns.map(function (conn) {
            $http.post('api/query/file', {
                conn: conn.key,
                hash: item.hash
            }).success(function (data) {
                console.log(data);
            })
        })
    }
});